//
//  WJPermanentThread.m
//  线程保活
//
//  Created by wangjian on 2020/7/7.
//  Copyright © 2020 wangjian. All rights reserved.
//

#import "WJPermanentThread.h"

@interface WJThread : NSThread

@end

@implementation WJThread

- (void)dealloc {
    NSLog(@"%s",__func__);
}

@end

@interface WJPermanentThread ()
@property(nonatomic,strong) WJThread *innerThread;
@property(nonatomic,assign,getter=isStoped)BOOL stoped;
@end

@implementation WJPermanentThread

- (instancetype)init {
    if (self = [super init]) {
        
        self.stoped = NO;
        __weak typeof(self) weakSelf = self;
        self.innerThread = [[WJThread alloc] initWithBlock:^{
            NSLog(@"thread---start");
            
            [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
            
            //添加判断 weakSelf，是防止weakSelf为null时，！weakSelf.isStoped的值就是YES。
            //那么runloop就不会真正的停止
            // 注意此处使用while 而不是使用if！！！
            while (weakSelf && !weakSelf.isStoped) {
                [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
            }
            
            NSLog(@"thread---end");
        }];
        [self.innerThread start];
    }
    
    return self;
}

- (void)executeTask:(WJPermanentThreadTask)task {
    
     if (!self.innerThread || !task) return;
    
        //在子线程中调用task
        //这里untilDone使用NO即可
        [self performSelector:@selector(__excuteTask:) onThread:self.innerThread withObject:task waitUntilDone:NO];
}

- (void)stop{
    
    if (!self.innerThread) {
        return;
    }
    /*
     这里untilDone需要使用YES。因为stop方法可能在dealloc中执行，那么是为了当runloop中while判断时，weakself不成为野指针。
     
     因为如果是用了NO，那么如果stop方法是在dealloc方法中调用，那么使用NO:
     就有可能当whle (weakSelf && !weakSelf.isStoped)判断时，出现坏内存访问。
     
     那么如果使用了YES，那么dealloc就会等着调用完毕stop方法后，才会继续执行。
     */
    [self performSelector:@selector(__stop) onThread:self.innerThread withObject:nil waitUntilDone:YES];
}

#pragma mark - private methods
- (void)__excuteTask:(WJPermanentThreadTask)task {
    task();
}

- (void)__stop {
    self.stoped = YES;
    CFRunLoopStop(CFRunLoopGetCurrent());
    self.innerThread = nil;
}

- (void)dealloc {
    NSLog(@"%s",__func__);
    
    [self stop];
}

@end
